package study_2;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 竞态实例
 * 描述：某系统为了便于跟踪对其接收到的HTTP请求的处理，会为其收到的每个HTTP请求分配一个唯一编号（RequestID）.
 * RequestID是一个固定长度的编码字符串，其中最后3位是一个在0-999循环递增（即从“000”递增到“999”，接着又从“000”开始递增）的序列号。
 * 我们很容易就可以写一个这样的Request ID生成器
 *
 * 防止竞态的方式：
 *  1.不必要的情况下，使用局部变量。
 *  2.使用 synchronized 对处理数据的方法进行修饰。
 */
public class RequestIdGenerator {
    /**
     * 保存该类唯一实例
     */
    private final static RequestIdGenerator INSTANCE = new RequestIdGenerator();
    private final static short SEQ_UPPER_LIMIT = 999;
    private short sequence = -1;


    //私有构造器
    private RequestIdGenerator(){
        //什么也不做
    }

    /**
     * 生成循环递增序列号
     * @return
     */
    public /*synchronized*/ short nextSequence(){
        if(sequence >= SEQ_UPPER_LIMIT){
            sequence = 0;
        }else{
            sequence++;
        }
        return sequence;
    }

    /**
     * 生成一个新的Request ID
     * @return
     */
    public String nextID(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmss");
        String timestamp = sdf.format(new Date());
        DecimalFormat df = new DecimalFormat("000");

        //生成请求序列号
        short sequenceNo = nextSequence();
        return String.format("0049" + timestamp + df.format(sequenceNo));
    }

    public static RequestIdGenerator getInstance(){
        return INSTANCE;
    }

    /**
     * 使用局部变量就不会产生竞态，但是无法实现多线程协助处理同一数据
     * @param sequence
     * @return
     */
    public int nextSequence(int sequence){
        //以下语句使用的是局部变量而非状态变量，并不会产生竞态
        if (sequence >= 999){
            sequence = 0;
        }else{
            sequence ++;
        }
        return sequence;
    }

}
